home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
mx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
29KB
|
1,384 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mutt.h"
#include "mx.h"
#include "send.h"
#include "rfc2047.h"
#include "sort.h"
#include "mailbox.h"
#include "state.h"
#include "parse.h"
#include "copy.h"
#ifdef _PGPPATH
#include "pgp.h"
#endif
#ifdef BUFFY_SIZE
#include "buffy.h"
#endif
#include <dirent.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifndef BUFFY_SIZE
#include <utime.h>
#endif
/* HP-UX and ConvexOS don't have this macro */
#ifndef S_ISLNK
#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK ? 1 : 0)
#endif
#define mutt_is_spool(s) (strcmp (Spoolfile, s) == 0)
#define MAXLOCKATTEMPT 5
#ifdef USE_DOTLOCK
static int dotlock_file (const char *path)
{
const char *pathptr = path;
char lockfile[_POSIX_PATH_MAX];
char nfslockfile[_POSIX_PATH_MAX];
char realpath[_POSIX_PATH_MAX];
struct stat sb;
int count = 0;
int fd;
/* if the file is a symlink, find the real file to which it refers */
FOREVER
{
dprint(2,(debugfile,"dotlock_file(): locking %s\n", pathptr));
if (lstat (pathptr, &sb) != 0)
{
mutt_perror (pathptr);
return (-1);
}
if (S_ISLNK (sb.st_mode))
{
char linkfile[_POSIX_PATH_MAX];
char linkpath[_POSIX_PATH_MAX];
if ((count = readlink (pathptr, linkfile, sizeof (linkfile))) == -1)
{
mutt_perror (path);
return (-1);
}
linkfile[count] = 0; /* readlink() does not NUL terminate the string! */
mutt_expand_link (linkpath, pathptr, linkfile);
strfcpy (realpath, linkpath, sizeof (realpath));
pathptr = realpath;
}
else
break;
}
snprintf (nfslockfile, sizeof (nfslockfile), "%s.%s.%d", pathptr, Hostname, (int) getpid ());
snprintf (lockfile, sizeof (lockfile), "%s.lock", pathptr);
unlink (nfslockfile);
while ((fd = open (nfslockfile, O_WRONLY | O_EXCL | O_CREAT, 0)) < 0)
if (errno != EAGAIN)
{
mutt_perror ("cannot open NFS lock file!");
return (-1);
}
close (fd);
count = 0;
FOREVER
{
link (nfslockfile, lockfile);
if (stat (nfslockfile, &sb) != 0)
{
mutt_perror ("stat");
return (-1);
}
if (sb.st_nlink == 2)
break;
if (++count == MAXLOCKATTEMPT)
{
if (mutt_yesorno ("Lock count exceeded, remove lock?", 1) == 1)
{
unlink (lockfile);
count = 0;
continue;
}
else
return (-1);
}
mutt_message ("Waiting for lock attempt #%d...", count);
sleep (1);
}
unlink (nfslockfile);
return 0;
}
static int undotlock_file (const char *path)
{
const char *pathptr = path;
char lockfile[_POSIX_PATH_MAX];
char realpath[_POSIX_PATH_MAX];
struct stat sb;
int n;
FOREVER
{
dprint (2,(debugfile,"undotlock: unlocking %s\n",path));
if (lstat (pathptr, &sb) != 0)
{
mutt_perror (pathptr);
return (-1);
}
if (S_ISLNK (sb.st_mode))
{
char linkfile[_POSIX_PATH_MAX];
char linkpath[_POSIX_PATH_MAX];
if ((n = readlink (pathptr, linkfile, sizeof (linkfile))) == -1)
{
mutt_perror (pathptr);
return (-1);
}
linkfile[n] = 0; /* readlink() does not NUL terminate the string! */
mutt_expand_link (linkpath, pathptr, linkfile);
strfcpy (realpath, linkpath, sizeof (realpath));
pathptr = realpath;
continue;
}
else
break;
}
snprintf (lockfile, sizeof (lockfile), "%s.lock", pathptr);
unlink (lockfile);
return 0;
}
#endif /* USE_DOTLOCK */
/* Args:
* excl if excl != 0, request an exclusive lock
* dot if dot != 0, try to dotlock the file
*/
int mx_lock_file (const char *path, int fd, int excl, int dot)
{
#if defined (USE_FCNTL) || defined (USE_FLOCK)
int count;
#endif
int r = 0;
#ifdef USE_FCNTL
struct flock lck;
memset (&lck, 0, sizeof (struct flock));
lck.l_type = excl ? F_WRLCK : F_RDLCK;
lck.l_whence = SEEK_SET;
count = 0;
while (fcntl (fd, F_SETLK, &lck) == -1)
{
dprint(1,(debugfile, "mx_lock_file(): fcntl errno %d.\n", errno));
if (errno != EAGAIN && errno != EACCES)
{
mutt_perror ("fcntl");
return (-1);
}
if (++count == MAXLOCKATTEMPT)
{
mutt_error ("Timeout exceeded while attempting fcntl lock!");
return (-1);
}
mutt_message ("Waiting for fcntl lock... %d", count);
sleep (1);
}
#endif /* USE_FCNTL */
#ifdef USE_FLOCK
count = 0;
while (flock (fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1)
{
if (errno != EWOULDBLOCK)
{
mutt_perror ("flock");
r = -1;
break;
}
if (++count == MAXLOCKATTEMPT)
{
mutt_error ("Timeout exceeded while attempting flock lock!");
r = -1;
break;
}
mutt_message ("Waiting for flock attempt... %d", count);
sleep (1);
}
#endif /* USE_FLOCK */
#ifdef USE_DOTLOCK
if (r == 0 && dot)
r = dotlock_file (path);
#endif /* USE_DOTLOCK */
if (r == -1)
{
/* release any other locks obtained in this routine */
#ifdef USE_FCNTL
lck.l_type = F_UNLCK;
fcntl (fd, F_SETLK, &lck);
#endif /* USE_FCNTL */
#ifdef USE_FLOCK
flock (fd, LOCK_UN);
#endif /* USE_FLOCK */
return (-1);
}
return 0;
}
int mx_unlock_file (const char *path, int fd)
{
#ifdef USE_FCNTL
struct flock unlockit = { F_UNLCK, 0, 0, 0 };
memset (&unlockit, 0, sizeof (struct flock));
unlockit.l_type = F_UNLCK;
unlockit.l_whence = SEEK_SET;
fcntl (fd, F_SETLK, &unlockit);
#endif
#ifdef USE_FLOCK
flock (fd, LOCK_UN);
#endif
#ifdef USE_DOTLOCK
undotlock_file (path);
#endif
return 0;
}
/* open a file and lock it */
FILE *mx_open_file_lock (const char *path, const char *mode)
{
FILE *f;
if ((f = fopen (path, mode)) != NULL)
{
if (mx_lock_file (path, fileno (f), *mode != 'r', 1) != 0)
{
fclose (f);
f = NULL;
}
}
return (f);
}
/* try to figure out what type of mailbox ``path'' is
*
* return values:
* M_* mailbox type
* 0 not a mailbox
* -1 error
*/
int mx_get_magic (const char *path)
{
struct stat st;
int magic = 0;
char tmp[_POSIX_PATH_MAX];
FILE *f;
#ifdef USE_IMAP
if (*path == '{')
return M_IMAP;
#endif /* USE_IMAP */
if (stat (path, &st) == -1)
{
dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
path, strerror (errno), errno));
mutt_perror (path);
return (-1);
}
if (S_ISDIR (st.st_mode))
{
/* check for maildir-style mailbox */
snprintf (tmp, sizeof (tmp), "%s/cur", path);
if (stat (tmp, &st) == 0 && S_ISDIR (st.st_mode))
return (M_MAILDIR);
/* check for mh-style mailbox */
snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", path);
if (access (tmp, F_OK) == 0)
return (M_MH);
snprintf (tmp, sizeof (tmp), "%s/.xmhcache", path);
if (access (tmp, F_OK) == 0)
return (M_MH);
}
else if (st.st_size == 0)
{
/* hard to tell what zero-length files are, so assume the default magic */
if (DefaultMagic == M_MBOX || DefaultMagic == M_MMDF)
return (DefaultMagic);
else
return (M_MBOX);
}
else if ((f = fopen (path, "r")) != NULL)
{
#ifndef BUFFY_SIZE
struct utimbuf times;
#endif
fgets (tmp, sizeof (tmp), f);
if (strncmp ("From ", tmp, 5) == 0)
magic = M_MBOX;
else if (strcmp (MMDF_SEP, tmp) == 0)
magic = M_MMDF;